//
//  XPNetworkApi.swift
//  PPKit
//
//  Created by xiaopin on 2019/7/16.
//  Copyright © 2019 PPKit. All rights reserved.
//  https://gitee.com/xiaopindev/PPKit
//  https://github.com/xiaopindev
//  https://xiaopin.cnblogs.com

import Foundation
import Alamofire
import SwiftyJSON
import HandyJSON

/// 网络API
class XPNetworkApi {
    //MARK: 单例写法
    static let shared = XPNetworkApi()
    
    private init(){}
    
    //MARK: 普通请求
    /// API Post请求
    /// - Parameters:
    ///   - url: 请求地址，如：https://api.mm.com/aa/bbb，参数名规范要求>> 固定：url
    ///   - parameters: 参数值，参数名规范要求>> 固定：parameters
    ///   - timeout: 超时设定，单位秒，默认5秒
    ///   - finishHander: 成功回调，在Api调用的时候公共基类post和get返回的时候，参数值规范要求：（msg，count, data）, 从ViewController和UIView等视图子类的时候，接口调用参数值规范：（msg, count, resObj）
    ///   - failedHander: 失败回调，参数值规范要求：（msg, code）
    func post(_ url:String,_ parameters:Parameters?=nil, timeout:TimeInterval = 15.0, _ finishedHandler:FinishedHandler?=nil,failed failedHandler:FailedHandler?=nil){
        DispatchQueue.global(qos: .utility).async {
            let startTime = NTPTime.shared.ntpTimestamp()
            let userAgent = "MaoTi(v\(pp_AppVersion)/\(pp_DeviceSystemName) \(pp_DeviceSystemVersion)/\(pp_DeviceModelName)/\(pp_networkStr()))"
            var cid = pp_uuid()
            var headers:HTTPHeaders = [
                "Content-Type":"application/json",
                "Api-Version":ApiVersion,
                "Version":pp_AppVersion,
                "Version-name":pp_AppBuildVersion,
                "Device":"iOS",
                "Device-Model":"iOS",
                "Drives":userAgent,
                "Screen-Size":"\(pp_screen_width.i)x\(pp_screen_height.i)",
                "Unique-Device":cid
            ]
            headers["User-Agent"] = userAgent
            headers["Web-Token"] = currentToken()
            
            var urlRequest = try? URLRequest(url: url, method: .post, headers: headers)
            urlRequest?.timeoutInterval = timeout
            if parameters != nil {
                urlRequest?.httpBody = pp_json_toData(parameters!)
            }
            //PPLog("Api (\(url)) post before > Thread isMainThread = \(Thread.isMainThread)")  // false
            AF.request(urlRequest!).responseJSON { (response) in
            //AF.request(url, method: .post, parameters: parameters, headers: headers).responseJSON { (response) in
                if SHOW_API_RESPONSE_LOG {
                    PPLog("API Post 请求URL：\(url))")
                    PPLog("API Post 请求参数: \(String(describing: parameters))")
                }
                let code = response.response?.statusCode ?? 9999
                var info:[String:Any] = ["url":url,
                                         "params":parameters ?? [:],
                                         "method":"post",
                                         "statusCode":code,
                                         "Token":currentToken(),
                                         "isMainThread":Thread.isMainThread]
                
                let finishedTime = NTPTime.shared.ntpTimestamp()
                let millseconds = (finishedTime - startTime) * 1000
                info["timeConsuming"] = String(format: "%.f", millseconds) + "ms"
                
                switch response.result {
                case let .success(value):
                    info["reponseResult"] = "success"
                    if response.response?.statusCode == 200 {
                        let json = JSON(value)
                        let resObject = XPResponse()
                        resObject.code = json["ret"].intValue
                        resObject.msg = json["msg"].stringValue
                        //resObject.count = json["count"].intValue
                        resObject.data = json["data"].rawValue
                        PPLog("API Post 请求✅:\(info)")
                        if SHOW_API_RESPONSE_LOG {
                            PPLog("API Post 请求结果Response: \(json)")
                        }
                        guard resObject.code == 0 else{
                            //请求成功，但是业务逻辑不对
                            /*
                             118:账号已过期！
                             119:此账号已在其它设备登录！
                             139:当前用户被封号！
                             20011:账号异常
                             20020:此账号已经注销、请重新注册
                             */
                            if resObject.code == 118 || resObject.code == 119 || resObject.code == 139 || resObject.code == 20011 || resObject.code == 20020{
                                XPApplication.shared.logout()
                            }
                            
                            failedHandler?("[\(resObject.code)]\(resObject.msg)", resObject.code)
                            return
                        }
                        //请求成功，并且业务逻辑正确
                        finishedHandler?(resObject.msg,resObject.count,resObject.data)
                    }else{
                        var msg = response.error?.localizedDescription ?? "请求响应非200错误"
                        info["localizedDescription"] = msg
                        if XPApplication.shared.netEnv == .unavailable{
                            msg = "[\(code)]:\(kMsgNetworkClosed.localized)"
                        }else if code == 408 || msg.contains("超时"){
                            msg = "[\(code)]:\(kMsgNetworkTimeout.localized)"
                        }else if msg.contains("似乎已断开与互联网的连接"){
                            msg = "[\(code)]:\(kMsgNetworkInterrupt.localized)"
                        }else if msg.contains(find: "JSON could not be serialized") || msg.contains(find: "格式不正确"){
                            msg = "[\(code)]:\(kMsgResponseJSONError.localized)"
                        }else{
                            if code >= 400 {
                                msg = "[\(code)]:\(kMsgServerError.localized)"
                            }
                        }
                        info["customDescription"] = msg
                        failedHandler?(msg, code)
                        PPLog("API Post 请求❎:\(info)")
                        DispatchQueue.global(qos: .background).async {
                            Bugly.report(NSException(name: NSExceptionName("网络请求非200错误"), reason: "直接响应回调到success, 状态码:\(code),\(msg)", userInfo: info))
                        }
                    }
                case let .failure(error):
                    info["reponseResult"] = "failure"
                    var msg = error.localizedDescription
                    info["localizedDescription"] = msg
                    if XPApplication.shared.netEnv == .unavailable{
                        msg = "[\(code)]:\(kMsgNetworkClosed.localized)"
                    }else if code == 408 || msg.contains("超时"){
                        msg = "[\(code)]:\(kMsgNetworkTimeout.localized)"
                    }else if msg.contains("似乎已断开与互联网的连接"){
                        msg = "[\(code)]:\(kMsgNetworkInterrupt.localized)"
                    }else if msg.contains(find: "JSON could not be serialized") || msg.contains(find: "格式不正确"){
                        msg = "[\(code)]:\(kMsgResponseJSONError.localized)"
                    }else{
                        if code >= 400 {
                            msg = "[\(code)]:\(kMsgServerError.localized)"
                        }
                    }
                    info["customDescription"] = msg
                    failedHandler?(msg, code)
                    PPLog("API Post 请求❎❎:\(info)")
                    DispatchQueue.global(qos: .background).async {
                        Bugly.report(NSException(name: NSExceptionName("网络请求失败"), reason: "直接响应回调到failure, 状态码:\(code),\(msg)", userInfo: info))
                    }
                }
            }
        }
    }
    
    /// API Get请求
    /// - Parameters:
    ///   - url: 请求地址，如：https://api.mm.com/aa/bbb，参数名规范要求>> 固定：url
    ///   - parameters: 参数值，参数名规范要求>> 固定：parameters
    ///   - timeout: 超时设定，单位秒，默认5秒
    ///   - finishHander: 成功回调，在Api调用的时候公共基类post和get返回的时候，参数值规范要求：（msg，count, data）, 从ViewController和UIView等视图子类的时候，接口调用参数值规范：（msg, count, resObj）
    ///   - failedHander: 失败回调，参数值规范要求：（msg, code）
    func get(_ url:String, _ parameters:[String:Any]?=nil, timeout:TimeInterval = 15.0, _ finishedHandler:FinishedHandler?=nil,failed failedHandler:FailedHandler?=nil){
        DispatchQueue.global(qos: .utility).async {
            let startTime = NTPTime.shared.ntpTimestamp()
            let userAgent = "MaoTi(v\(pp_AppVersion)/\(pp_DeviceSystemName) \(pp_DeviceSystemVersion)/\(pp_DeviceModelName)/\(pp_networkStr()))"
            var cid = pp_uuid()
//            if let visitor = XPApplication.shared.visitorInfo, let value = visitor["cid"] as? String {
//                cid = value
//            }
            var headers:HTTPHeaders = [
                "Content-Type":"application/json",
                "Api-Version":ApiVersion,
                "Version":pp_AppVersion,
                "Version-name":pp_AppBuildVersion,
                "Device":"iOS",
                "Device-Model":"iOS",
                "Drives":userAgent,
                "Screen-Size":"\(pp_screen_width.i)x\(pp_screen_height.i)",
                "Unique-Device":cid
            ]
            headers["User-Agent"] = userAgent
            headers["Web-Token"] = currentToken()

            AF.request(url, method: .get, parameters: parameters, headers: headers, requestModifier: {$0.timeoutInterval = timeout}).responseJSON { (response) in
                if SHOW_API_RESPONSE_LOG {
                    PPLog("API Get 请求URL：\(url))")
                    PPLog("API Get 请求参数: \(String(describing: parameters))")
                }
                let code = response.response?.statusCode ?? 9999
                var info:[String:Any] = ["url":url,
                                         "params":parameters ?? [:],
                                         "method":"get",
                                         "statusCode":code,
                                         "Token":currentToken(),
                                         "isMainThread":Thread.isMainThread]
                
                let finishedTime = NTPTime.shared.ntpTimestamp()
                let millseconds = (finishedTime - startTime) * 1000
                info["timeConsuming"] = String(format: "%.f", millseconds) + "ms"
                
                switch response.result {
                case let .success(value):
                    info["reponseResult"] = "success"
                    if response.response?.statusCode == 200 {
                        let json = JSON(value)
                        let resObject = XPResponse()
                        
                        resObject.code = json["ret"].intValue
                        resObject.msg = json["msg"].stringValue
                        //resObject.count = json["count"].intValue
                        resObject.data = json["data"].rawValue
                        PPLog("API Get 请求✅:\(info)")
                        if SHOW_API_RESPONSE_LOG {
                            PPLog("API Get 请求结果Response: \(json)")
                        }
                        guard resObject.code == 0 else{
                            //请求成功，但是业务逻辑不对
                            /*
                             118:账号已过期！
                             119:此账号已在其它设备登录！
                             139:当前用户被封号！
                             20011:账号异常
                             20020:此账号已经注销、请重新注册
                             */
                            if resObject.code == 118 || resObject.code == 119 || resObject.code == 139 || resObject.code == 20011 || resObject.code == 20020{
                                XPApplication.shared.logout()
                            }
                            
                            failedHandler?("[\(resObject.code)]\(resObject.msg)", resObject.code)
                            return
                        }
                        //请求成功，并且业务逻辑正确
                        finishedHandler?(resObject.msg,resObject.count,resObject.data)
                    }else{
                        var msg = response.error?.localizedDescription ?? "请求响应非200错误"
                        info["localizedDescription"] = msg
                        if XPApplication.shared.netEnv == .unavailable{
                            msg = "[\(code)]:\(kMsgNetworkClosed.localized)"
                        }else if code == 408 || msg.contains("超时"){
                            msg = "[\(code)]:\(kMsgNetworkTimeout.localized)"
                        }else if msg.contains("似乎已断开与互联网的连接"){
                            msg = "[\(code)]:\(kMsgNetworkInterrupt.localized)"
                        }else if msg.contains(find: "JSON could not be serialized") || msg.contains(find: "格式不正确"){
                            msg = "[\(code)]:\(kMsgResponseJSONError.localized)"
                        }else{
                            if code >= 400 {
                                msg = "[\(code)]:\(kMsgServerError.localized)"
                            }
                        }
                        info["customDescription"] = msg
                        failedHandler?(msg, code)
                        PPLog("API Get 请求❎:\(info)")
                        DispatchQueue.global(qos: .background).async {
                            Bugly.report(NSException(name: NSExceptionName("网络请求非200错误"), reason: "直接响应回调到success, 状态码:\(code),\(msg)", userInfo: info))
                        }
                    }
                case let .failure(error):
                    info["reponseResult"] = "failure"
                    var msg = error.localizedDescription
                    info["localizedDescription"] = msg
                    if XPApplication.shared.netEnv == .unavailable{
                        msg = "[\(code)]:\(kMsgNetworkClosed.localized)"
                    }else if code == 408 || msg.contains("超时"){
                        msg = "[\(code)]:\(kMsgNetworkTimeout.localized)"
                    }else if msg.contains("似乎已断开与互联网的连接"){
                        msg = "[\(code)]:\(kMsgNetworkInterrupt.localized)"
                    }else if msg.contains(find: "JSON could not be serialized") || msg.contains(find: "格式不正确"){
                        msg = "[\(code)]:\(kMsgResponseJSONError.localized)"
                    }else{
                        if code >= 400 {
                            msg = "[\(code)]:\(kMsgServerError.localized)"
                        }
                    }
                    info["customDescription"] = msg
                    failedHandler?(msg, code)
                    PPLog("API Get 请求❎❎:\(info)")
                    DispatchQueue.global(qos: .background).async {
                        Bugly.report(NSException(name: NSExceptionName("网络请求失败"), reason: "直接响应回调到failure, 状态码:\(code),\(msg)", userInfo: info))
                    }
                }
            }
        }
    }
    
    /// API 请求
    /// - Parameters:
    ///   - url: 请求地址，如：https://api.mm.com/aa/bbb，参数名规范要求>> 固定：url
    ///   - method: 请求方式
    ///   - parameters: 参数值，参数名规范要求>> 固定：parameters
    ///   - timeout: 超时设定，单位秒，默认5秒
    ///   - finishHander: 成功回调，在Api调用的时候公共基类post和get返回的时候，参数值规范要求：（msg，count, data）, 从ViewController和UIView等视图子类的时候，接口调用参数值规范：（msg, count, resObj）
    ///   - failedHander: 失败回调，参数值规范要求：（msg, code）
    func h5request(_ url:String, method:HTTPMethod = .post,_ parameters:Parameters?=nil, timeout:TimeInterval = 15.0, _ finishedHandler:FinishedHandler?=nil,failed failedHandler:FailedHandler?=nil){
        let userAgent = "MaoTi(v\(pp_AppVersion)/\(pp_DeviceSystemName) \(pp_DeviceSystemVersion)/\(pp_DeviceModelName)/\(pp_networkStr()))"
        var cid = pp_uuid()
        
        var headers:HTTPHeaders = [
            "Content-Type":"application/json",
            "Api-Version":ApiVersion,
            "Version":pp_AppVersion,
            "Version-name":pp_AppBuildVersion,
            "Device":"iOS",
            "Device-Model":"iOS",
            "Drives":userAgent,
            "Screen-Size":"\(pp_screen_width.i)x\(pp_screen_height.i)",
            "Unique-Device":cid
        ]
        headers["User-Agent"] = userAgent
        headers["Web-Token"] = currentToken()
        
        var urlRequest = try? URLRequest(url: url, method: method, headers: headers)
        urlRequest?.timeoutInterval = timeout
        if parameters != nil {
            urlRequest?.httpBody = pp_json_toData(parameters!)
        }
        AF.request(urlRequest!).responseJSON { (response) in
            if SHOW_API_RESPONSE_LOG {
                PPLog("请求URL：\(url))")
                PPLog("请求参数: \(String(describing: parameters))")
            }
            switch response.result {
            case let .success(value):
                if response.response?.statusCode == 200 {
                    let json = JSON(value)
                    let resObject = XPResponse()
                    resObject.code = json["ret"].intValue
                    resObject.msg = json["msg"].stringValue
                    //resObject.count = json["count"].intValue
                    resObject.data = json["data"].rawValue
                    if SHOW_API_RESPONSE_LOG {
                        PPLog("请求结果Response: \(json)")
                    }
                    guard resObject.code == 0 else{
                        //请求成功，但是业务逻辑不对
                        /*
                         118:账号已过期！
                         119:此账号已在其它设备登录！
                         139:当前用户被封号！
                         20011:账号异常
                         20020:此账号已经注销、请重新注册
                         */
                        if resObject.code == 118 || resObject.code == 119 || resObject.code == 139 || resObject.code == 20011 || resObject.code == 20020{
                            XPApplication.shared.logout()
                        }
                        
                        failedHandler?("[\(resObject.code)]\(resObject.msg)", resObject.code)
                        return
                    }
                    //请求成功，并且业务逻辑正确
                    if let dict = value as? [String:Any] {
                        let jsonStr = pp_json_toString(dict)
                        finishedHandler?("", 0, jsonStr)
                    }
                }else{
                    let msg = response.error?.localizedDescription ?? "请求响应非200错误"
                    let code = response.response?.statusCode ?? 9999
                    PPLog("请求失败1：\(url) \(code): \(msg))")
                    if XPApplication.shared.netEnv == .unavailable{
                        failedHandler?("[S-\(code)]:\(kMsgNetworkClosed.localized)", code)
                    }else if code == 408 || msg.contains("超时"){
                        failedHandler?("[S-\(code)]:\(kMsgNetworkTimeout.localized)", code)
                    }else if msg.contains("似乎已断开与互联网的连接"){
                        failedHandler?("[S-\(code)]:\(kMsgNetworkInterrupt.localized)", code)
                    }else if msg.contains(find: "JSON could not be serialized") || msg.contains(find: "格式不正确"){
                        failedHandler?("[S-\(code)]\(kMsgResponseJSONError.localized)", code)
                    }else{
                        if code >= 400 {
                            failedHandler?("[S-\(code)]\(kMsgServerError.localized)", code)
                        }
                    }
                    DispatchQueue.global(qos: .background).async {
                        Bugly.report(NSException(name: NSExceptionName("网络请求非200"), reason: "直接响应回调到success, 状态码:\(code),\(msg)", userInfo: ["url":url,"params":parameters ?? [:],"code":code,"msg":msg]))
                    }
                }
            case let .failure(error):
                let msg = error.localizedDescription
                let code = error.responseCode ?? 9999
                PPLog("请求失败2：\(url) \(String(describing: code)): \(msg))")
                if XPApplication.shared.netEnv == .unavailable{
                    failedHandler?(kMsgNetworkClosed, code)
                }else if code == 408 || msg.contains("超时"){
                    failedHandler?("[\(code)]\(kMsgNetworkTimeout.localized)", code)
                }else if msg.contains("似乎已断开与互联网的连接"){
                    failedHandler?("[\(code)]\(kMsgNetworkInterrupt.localized)", code)
                }else if msg.contains(find: "JSON could not be serialized") || msg.contains(find: "格式不正确"){
                    failedHandler?("[\(code)]\(kMsgResponseJSONError.localized)", code)
                }else{
                    if code >= 400 {
                        failedHandler?("[\(code)]\(kMsgServerError.localized)", code)
                    }
                }
                DispatchQueue.global(qos: .background).async {
                    Bugly.report(NSException(name: NSExceptionName("网络请求失败"), reason: "直接响应回调到failure, 状态码:\(code),\(msg)", userInfo: ["url":url,"params":parameters ?? [:],"code":code,"error":error]))
                }
            }
        }
    }
    
    /// 请求一个json文件的值
    ///
    /// - Parameters:
    ///   - url: <#url description#>
    ///   - parameters: <#parameters description#>
    ///   - baseFinishedHandler: <#baseFinishedHandler description#>
    ///   - baseFailedHandler: <#baseFailedHandler description#>
    func getJsonValue(url:String,parameters:[String:Any]?=nil,_ finishedHandler:FinishedHandler?=nil,failed failedHandler:FailedHandler?=nil){
        PPLog("请求URL地址：\(url))")
        
        let urlRequest = URLRequest(url: URL(string: url)!, cachePolicy: .reloadIgnoringCacheData, timeoutInterval: 120)
        
        AF.request(urlRequest).responseJSON { (response) in
            switch response.result {
            case let .success(value):
                PPLog("请求成功：\(value)")
                finishedHandler?("请求成功",0,value as AnyObject)
            case let .failure(error):
                PPLog("请求失败：\(error.localizedDescription))")
            }
        }
    }

    //MARK: 文件上传、断点续传：图片、视频
    /// 文件上传、断点续传：图片、视频
    /// - Parameters:
    ///   - url: <#url description#>
    ///   - fileURL: <#fileURL description#>
    ///   - progressHandler: <#progressHandler description#>
    ///   - finishedHandler: <#finishedHandler description#>
    ///   - failedHandler: <#failedHandler description#>
    func upload(url:String, fileURL:URL, progress progressHandler:ProgressHandler? = nil, finished finishedHandler:FinishedHandler?=nil,failed failedHandler:FailedHandler?=nil){
        DispatchQueue.global(qos: .utility).async {
            if XPApplication.shared.netEnv == .unavailable{
                failedHandler?(kMsgNetworkClosed, 9999)
                return
            }
            let userAgent = "MaoTi(v\(pp_AppVersion)/\(pp_DeviceSystemName) \(pp_DeviceSystemVersion)/\(pp_DeviceModelName)/\(pp_networkStr()))"
            var cid = pp_uuid()
            var headers:HTTPHeaders = [
                "Content-Type":"application/json",
                "Api-Version":ApiVersion,
                "Version":pp_AppVersion,
                "Version-name":pp_AppBuildVersion,
                "Device":"iOS",
                "Device-Model":"iOS",
                "Drives":userAgent,
                "Screen-Size":"\(pp_screen_width.i)x\(pp_screen_height.i)",
                "Unique-Device":cid
            ]
            headers["User-Agent"] = userAgent
            headers["Web-Token"] = currentToken()
            
            let request = try? URLRequest(url: url, method: .post, headers: headers)
            
            AF.upload(multipartFormData: { (mfdata) in
                mfdata.append(fileURL, withName: "file")
            }, with: request!).uploadProgress { (progress) in
                progressHandler?(progress)
            }.responseJSON { (response) in
                let statusCode = response.response?.statusCode
                if statusCode == 200 || statusCode == 201{
                    finishedHandler?("上传成功",0, true)
                }else{
                    failedHandler?("上传失败",0)
                }
            }
        }
    }
    
    //MARK: 文件下载、断点下载
    /// 下载对象集合
    var downloaders = [XPDownload]()
    /// 下载线程队列
    let downloadsQueue = DispatchQueue(label: "com.alamofire.downloadsQueue", qos: .utility, attributes: .concurrent)
    
    /// 下载文件
    /// - Parameters:
    ///   - url: 文件网络地址
    ///   - destination: 文件存储目录
    ///   - progressHandler: 文件下载进度
    ///   - finishedHandler: 文件下载完成
    ///   - failedHandler: 文件下载失败
    func download(url:String, destination:String, progress progressHandler:ProgressHandler? = nil, finished finishedHandler:FinishedHandler?=nil,failed failedHandler:FailedHandler?=nil){
        downloadsQueue.async {
            //构建下载目标路径，自动创建新目录和替换旧文件
            let dest:DownloadRequest.Destination = { _,_ in
                return (URL(fileURLWithPath: destination), [.removePreviousFile, .createIntermediateDirectories])
            }
            
            let progressQueue = DispatchQueue(label: "com.alamofire.progressQueue", qos: .utility)
            var request:DownloadRequest?
            
            let resumeFilePath = XPSandbox.shared.buildDocsPath(.files, "\(url.MD5).download")
            if let data = try? Data.init(contentsOf: URL(fileURLWithPath: resumeFilePath)){
                //判断是否有断点数据,继续下载
                request = AF.download(resumingWith: data).downloadProgress(queue: progressQueue) { (progress) in
                    progressHandler?(progress)
                }
            }else{
                request = AF.download(url, to: dest).downloadProgress(queue: progressQueue) { (progress) in
                    progressHandler?(progress)
                }
            }
            
            if self.downloaders.contains(where: {$0.url == url}) == true{
                self.downloaders.first(where: {$0.url == url})?.request = request
            }else{
                let downloader = XPDownload()
                downloader.key = url.MD5
                downloader.url = url
                downloader.request = request
                downloader.localPath = destination
                downloader.resumePath = resumeFilePath
                //也指针 MTbase download
                self.downloaders.append(downloader)
            }
            
            request?.responseData { [weak self] (response) in
                PPLog("下载文件:\(response)")
                if let data = response.value{
                    //文件下载完成，存储文件到制定目录
                    finishedHandler?("下载完成",0, data)
                }else{
                    //文件下载失败
                    failedHandler?(response.error?.localizedDescription,0)
                }
                //从队列中移除
                self?.downloaders.removeAll(where: { (downloader) -> Bool in
                    return downloader.url == url
                })
                
                //如果有临时数据，移除临时数据
                XPSandbox.shared.removeFile(resumeFilePath)
            }
        }
    }
    
    /// 取消所有下载
    ///
    /// 暂停所有下载队列中的Á
    func cancelAllDownloads(){
        for downloader in downloaders {
            if downloader.request?.isCancelled == true { continue }
            
            //如果没有取消的，执行暂停，并存储临时断点数据
            downloader.request?.cancel(byProducingResumeData: { (data) in
                try? data?.write(to: URL(string: downloader.resumePath!)!)
            })
        }
    }
    
    /// 暂停指定下载
    /// - Parameter url: <#url description#>
    func cancelDownload(url:String){
        if let downloader = downloaders.first(where: {$0.url == url}) {
            downloader.request?.cancel(byProducingResumeData: { (data) in
                try? data?.write(to: URL(string: downloader.resumePath!)!)
            })
        }
    }
    
    /// 继续所有下载
    func resumeAllDownloads(){
        for downloader in downloaders {
            if downloader.request?.isCancelled == false { continue }
            
            //暂未开发
        }
    }
    
    //MARK: 其他
    /*
    /// 上报请求耗时
    /// - Parameters:
    ///   - id: <#urlStr description#>
    ///   - code: <#code description#>
    ///   - msg: <#msg description#>
    ///   - timeConsuming: <#timeConsuming description#>
    func report(_ id:Int, _ code:Int,_ msg:String?,_ timeConsuming:Double, _ desc:String = ""){
        let url = kApiDomain() + ApiPath.Common_ReportTimeConsuming.rawValue
        let userAgent = "MaoTi(v\(pp_AppVersion)/\(pp_DeviceSystemName) \(pp_DeviceSystemVersion)/\(pp_DeviceModelName)/\(pp_networkStr()))"
        var headers:HTTPHeaders = [
            "Content-Type":"application/json",
            "Channel-Name":AppTGChannel,
            "Api-Version":ApiVersion,
            "Version":pp_AppVersion,
            "Version-name":pp_AppBuildVersion,
            "Device":"iOS",
            "Device-Model":"iOS",
            "Drives":userAgent,
            "Screen-Size":"\(pp_screen_width.i)x\(pp_screen_height.i)",
            "Unique-Device":XPApplication.shared.pushToken.isNullOrEmpty() ? XPApplication.shared.pushToken : pp_uuid(),
            "IDFA":XPApplication.shared.idfaStr,
            "Origin-Id":MTAppId.str,
            "Language-Code":"en-US"
        ]
        headers["User-Agent"] = userAgent
        headers["Web-Token"] = currentToken()

        let parameters:[String:Any] = [
            "speed_id":id,
            "code":code,
            "msg":msg ?? "",
            "consuming":timeConsuming,
            "consuming_msg":desc
        ]
        
        var urlRequest = try? URLRequest(url: url, method: .post, headers: headers)
        urlRequest?.httpBody = pp_json_toData(parameters)
        AF.request(urlRequest!).responseJSON { (response) in
            switch response.result {
            case let .success(value):
                if response.response?.statusCode == 200 {
                    //PPLog("上报成功")
                }else{
                    
                }
            case let .failure(error):
                break
            }
        }
    }*/
}
